19.16 BackGroundWorker
 
In Kapitel 11 haben Sie bereits alles Wichtige im Zusammenhang mit den Threads kennen gelernt. In der Toolbox wird Ihnen mit BackgroundWorker noch eine weitere Möglichkeit angeboten, auf sehr einfache Weise einen Hintergrundthread ins Leben zu rufen, in dem neben dem UI-Thread zeitintensive Operationen ausgeführt werden können. Dazu ist noch nicht einmal notwendig, einen neuen Thread zu erzeugen, alles wird vom Steuerelement automatisch in die Hand genommen. Automatisch bedeutet natürlich nicht, dass Sie die Hände in den Schoß legen können. Aber die Eigenschaften, Methoden und Ereignisse sind von der Anzahl her überschaubar und leicht zu programmieren.
Nachdem Sie das Steuerelement in die Form gezogen haben, müssen Sie nur die Methode RunWorkerAsync aufrufen, um den neuen Thread zu starten. Die Methode ist überladen und gestattet neben dem parameterlosen Aufruf auch die Übergabe eines Arguments an die Thread-Operation. Da die Überladung vom Typ Object ist, können Sie innerhalb eines Arrays oder einer Collection natürlich auch beliebig viele Argumente übergeben.
RunWorkerAsync hat die Auslösung des Ereignisses DoWork zur Folge. Es ist eins von insgesamt drei Ereignissen des Steuerelements und auch das einzige, das nicht im Kontext des UI-, sondern in dem des Hintergrundthreads ausgeführt wird. Hier implementieren Sie die Operationen, die vom Hintergrundthread abgearbeitet werden sollen. Die übergebenen Argumente greifen Sie über die Eigenschaft Argument des DoWorkEventArgs-Objekts im Ereignishandler ab.
Der Aufrufer muss möglicherweise während der laufenden Operationen zwischenzeitlich vom aktuellen Stand der laufenden Operation informiert werden. Rufen Sie dazu nur die Methode ReportProgress auf das BackgroundWorker-Objekt auf, und übergeben Sie eine Zahl zwischen 0 und 100, die in Prozent den augenblicklichen Fortschritt beschreibt. Auch durch diesen Methodenaufruf wird ein Ereignis ausgelöst: ProgressChanged. Allerdings dürfen Sie nicht vergessen, vorher die Eigenschaft WorkerReportsProgress=true zu setzen. Ansonsten sehen Sie sich mit einer Exception konfrontiert.
RunWorkerCompleted ist das dritte Ereignis des BackgroundWorker-Objekts und wird ausgelöst, wenn der Hintergrundvorgang entweder abgeschlossen ist, abgebrochen wurde oder eine Ausnahme ausgelöst hat. Liefert die Operation ein abschließendes Resultat, rufen Sie das über die Eigenschaft Result des RunWorkerCompletedEventsArgs-Objekt ab.
Das wollen wir uns nun an einem Beispiel ansehen. Grundlage dazu soll das Beispiel sein, das im Zusammenhang mit der Vorstellung des ProgressBar-Steuerelements gezeigt wurde. Es soll nun so umgeschrieben werden, dass die länger andauernde Operation (das Lesen einer Textdatei) in einem durch BackgroundWorker bereitgestellten Hintergrundthread ausgeführt wird.
| // ---------------------------------------------------------
|
| // Beispiel: ...\Kapitel 19\BackgroundWorkerDemo
|
| // ---------------------------------------------------------
|
| public partial class Form1 : Form {
|
| private string file = @"C:\Test.txt";
|
| public Form1() {
|
| InitializeComponent();
|
| // Datei erzeugen und mit Zeichen füllen
|
| FileStream fs = File.Open(file, FileMode.Create);
|
| byte b = 97;
|
| for (int i = 0; i < 20000; i++) {
|
| fs.WriteByte(b++);
|
| if (b == 123) b = 97;
|
| }
|
| fs.Close();
|
| }
|
| private void button1_Click(object sender, EventArgs e) {
|
| textBox1.Clear();
|
| textBox1.Refresh();
|
| // ProgressBar einstellen
|
| proFuellen.Maximum = 100;
|
| proFuellen.Step = 1;
|
| proFuellen.Value = 0;
|
| // BackGroundWorker starten
|
| this.backgroundWorker1.RunWorkerAsync(file);
|
| }
|
| private void Form1_FormClosed(object sender, FormClosedEventArgs e) {
|
| File.Delete(file);
|
| }
|
| private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e){
|
| int var = 0;
|
| string text = "";
|
| // Datei öffnen
|
| FileStream fs = File.Open(e.Argument.ToString(), FileMode.Open);
|
| FileInfo fi = new FileInfo(file);
|
| // Dateigröße
|
| int fileLength = (int)new FileInfo(file).Length;
|
| int counter = 0;
|
| while (true) {
|
| var = fs.ReadByte();
|
| // wenn Datei eingelesen, Schleife beenden
|
| if (var == –1)
|
| break;
|
| text += Convert.ToChar(var);
|
| // Das Ereignis 'ProgressChanged' auslösen
|
| counter++;
|
| this.backgroundWorker1.ReportProgress(counter * 100 / fileLength);
|
| }
|
| e.Result = text;
|
| fs.Close();
|
| }
|
| private void backgroundWorker1_ProgressChanged(object sender,
|
| ProgressChangedEventArgs e) {
|
| // ProgressBar einstellen
|
| proFuellen.Value = e.ProgressPercentage;
|
| }
|
| private void backgroundWorker1_RunWorkerCompleted(object sender,
|
| RunWorkerCompletedEventArgs e) {
|
| this.textBox1.Text = Convert.ToString(e.Result);
|
| this.proFuellen.Value = 0;
|
| }
|
| }
|
| Hinweis Sie können das Steuerelement BackgroundWorker auch außerhalb von Windows-Anwendungen benutzen. Dazu instanziieren Sie die gleichnamige Klasse, die zum Namespace System.ComponentModel gehört.
|
|